import requests
import time
import hmac
import hashlib
import base64
import json
from urllib.parse import urlencode, quote_plus


class AlipayService:
    def __init__(self, app_id, app_private_key_path, alipay_public_key_path,
                 notify_url, return_url, sandbox=False):
        self.app_id = app_id
        self.app_private_key_path = app_private_key_path
        self.alipay_public_key_path = alipay_public_key_path
        self.notify_url = notify_url
        self.return_url = return_url
        self.sandbox = sandbox
        self.gateway = 'https://openapi.alipaydev.com/gateway.do' if sandbox else 'https://openapi.alipay.com/gateway.do'

    def _get_private_key(self):
        with open(self.app_private_key_path, 'r') as f:
            return f.read()

    def _get_public_key(self):
        with open(self.alipay_public_key_path, 'r') as f:
            return f.read()

    def _generate_sign(self, params, private_key):
        sorted_params = sorted(params.items(), key=lambda x: x[0])
        string_to_sign = '&'.join([f"{k}={v}" for k, v in sorted_params if v and k != 'sign'])
        sign = self._rsa_sign(string_to_sign, private_key)
        return sign

    def _rsa_sign(self, data, private_key):
        key = private_key
        signer = hmac.new(key.encode('utf8'), data.encode('utf8'), hashlib.sha256)
        signature = base64.b64encode(signer.digest()).decode()
        return signature

    def generate_auth_url(self, state=None):
        params = {
            'app_id': self.app_id,
            'method': 'alipay.system.oauth.token',
            'format': 'JSON',
            'charset': 'utf-8',
            'sign_type': 'RSA2',
            'timestamp': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()),
            'version': '1.0',
            'redirect_uri': self.return_url,
            'scope': 'auth_user',
            'state': state or 'random_state'
        }
        sign = self._generate_sign(params, self._get_private_key())
        params['sign'] = sign
        return f"https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?{urlencode(params)}"

    def get_access_token(self, auth_code):
        params = {
            'app_id': self.app_id,
            'method': 'alipay.system.oauth.token',
            'format': 'JSON',
            'charset': 'utf-8',
            'sign_type': 'RSA2',
            'timestamp': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()),
            'version': '1.0',
            'grant_type': 'authorization_code',
            'code': auth_code
        }
        sign = self._generate_sign(params, self._get_private_key())
        params['sign'] = sign
        response = requests.post(self.gateway, data=params)
        return response.json()

    def get_user_info(self, access_token):
        params = {
            'app_id': self.app_id,
            'method': 'alipay.user.info.share',
            'format': 'JSON',
            'charset': 'utf-8',
            'sign_type': 'RSA2',
            'timestamp': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()),
            'version': '1.0',
            'auth_token': access_token
        }
        sign = self._generate_sign(params, self._get_private_key())
        params['sign'] = sign
        response = requests.post(self.gateway, data=params)
        return response.json()
